using System;
using System.Collections.Generic;
using System.Linq;
using Shinkansen.Core;
using Shinkansen.Model;
using Shinkansen.Runtime;
using Shinkansen.UI;

namespace Shinkansen.Web.UI.WebControls
{
    public class JavaScriptTagBuilder : TagBuilderBase
    {
        private readonly ShinkansenOptions _options;
        private readonly IEnumerable<JavaScriptInclude> _jsIncludes;
        private readonly Action<string> _registrationCallback;

        /// <summary>
        /// Initializes a new instance of the <see cref="JavaScriptTagBuilder"/> class.
        /// </summary>
        /// <param name="options">The options.</param>
        /// <param name="jsIncludes">The js includes.</param>
        /// <param name="registrationCallback">The tag registrar.</param>
        public JavaScriptTagBuilder (ShinkansenOptions options, IEnumerable<JavaScriptInclude> jsIncludes, Action<string> registrationCallback)
        {
            _options = options;
            _jsIncludes = jsIncludes;
            _registrationCallback = registrationCallback;
        }

        /// <summary>
        /// Processes JavaScript includes.
        /// </summary>
        public override void Run ()
        {
            if (!_jsIncludes.Any ())
                return;

            Action actor = _options.Combine
               ? (Action)(CombineAllJavaScript)
               : RegisterIndividualJsResources;

            actor ();
        }

        /// <summary>
        /// Combines all resources.
        /// </summary>
        private void CombineAllJavaScript ()
        {
            IEnumerable<IStaticInclude> js = _jsIncludes.Cast<IStaticInclude> ();

            IQueryStringBuilder builder = 
                new QueryStringForJavaScriptBuilder (
                    new QueryStringWithCompressionBuilder (
                        new QueryStringWithCrunchingBuilder (
                            new CombinedQueryStringBuilder (js), _options.Crunch), _options.HttpCompressWith));

            EncryptedQueryString qs = new EncryptedQueryString ();
            builder.ConstructQueryString (qs);

            string tag = BuildScriptTag (qs);
            _registrationCallback (tag);
        }

        /// <summary>
        /// Registers the individual resources.
        /// </summary>
        private void RegisterIndividualJsResources ()
        {
            foreach (JavaScriptInclude js in _jsIncludes)
            {
                IQueryStringBuilder builder = 
                    new QueryStringForJavaScriptBuilder (
                        new QueryStringWithCompressionBuilder (
                            new QueryStringWithCrunchingBuilder (
                                new IndividualQueryStringBuilder (js), _options.Crunch), _options.HttpCompressWith));

                EncryptedQueryString qs = new EncryptedQueryString ();
                builder.ConstructQueryString (qs);

                string tag = BuildScriptTag (qs);
                _registrationCallback (tag);
            }
        }

        /// <summary>
        /// Builds the script tag.
        /// </summary>
        /// <param name="qs">The qs.</param>
        /// <returns></returns>
        private string BuildScriptTag (QueryString qs)
        {
            return string.Format ("<script src='{0}?{1}={2}' type='text/javascript'></script>\n", PathToAxd, Tokens.SecureToken, qs);
        }
    }
}
